/*
 * Copyright (c) 2012-2018 Red Hat, Inc.
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Red Hat, Inc. - initial API and implementation
 */
package org.eclipse.che.ide.command.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.List;
import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseProvider;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.command.CommandImpl;
import org.eclipse.che.ide.api.command.CommandManager;
import org.eclipse.che.ide.api.command.CommandType;
import org.eclipse.che.ide.api.workspace.model.WorkspaceConfigImpl;
import org.eclipse.che.ide.api.workspace.model.WorkspaceImpl;
import org.eclipse.che.ide.context.AppContextImpl;
import org.eclipse.che.ide.workspace.WorkspaceServiceClient;

/** Responsible for managing the commands which are stored with workspace. */
@Singleton
class WorkspaceCommandManagerDelegate {

  private final WorkspaceServiceClient workspaceServiceClient;
  private final AppContext appContext;
  private PromiseProvider promiseProvider;

  @Inject
  WorkspaceCommandManagerDelegate(
      WorkspaceServiceClient workspaceServiceClient,
      AppContext appContext,
      PromiseProvider promiseProvider) {
    this.workspaceServiceClient = workspaceServiceClient;
    this.appContext = appContext;
    this.promiseProvider = promiseProvider;
  }

  /** Returns commands which are stored in the current workspace. */
  List<CommandImpl> getCommands() {
    final WorkspaceImpl workspace = appContext.getWorkspace();
    final WorkspaceConfigImpl workspaceConfig = workspace.getConfig();

    return workspaceConfig.getCommands();
  }

  /** Updates the commands. */
  Promise<List<CommandImpl>> fetchCommands() {
    return workspaceServiceClient
        .getWorkspace(appContext.getWorkspaceId())
        .thenPromise(
            workspace -> {
              updateWorkspace().apply(workspace);
              return promiseProvider.resolve(getCommands());
            });
  }

  /**
   * Creates new command of the specified type.
   *
   * <p><b>Note</b> that command's name will be generated by {@link CommandManager} and command line
   * will be provided by an appropriate {@link CommandType}.
   */
  Promise<Void> createCommand(final CommandImpl command) {
    return workspaceServiceClient
        .addCommand(appContext.getWorkspaceId(), command)
        .then(updateWorkspace());
  }

  /**
   * Updates the command with the specified {@code name} by replacing it with the given {@code
   * command}.
   *
   * <p><b>Note</b> that name of the updated command may differ from the name provided by the given
   * {@code command} in order to prevent name duplication.
   */
  Promise<Void> updateCommand(final CommandImpl command) {
    return workspaceServiceClient
        .updateCommand(appContext.getWorkspaceId(), command.getName(), command)
        .then(updateWorkspace());
  }

  /** Removes the command with the specified {@code commandName}. */
  Promise<Void> removeCommand(String commandName) {
    return workspaceServiceClient
        .deleteCommand(appContext.getWorkspaceId(), commandName)
        .thenPromise(
            arg ->
                workspaceServiceClient
                    .getWorkspace(appContext.getWorkspaceId())
                    .then(updateWorkspace()));
  }

  private Function<WorkspaceImpl, Void> updateWorkspace() {
    return workspace -> {
      // update workspace model in AppContext because
      // AppContext always must return an actual workspace model
      ((AppContextImpl) appContext).setWorkspace(workspace);

      return null;
    };
  }
}
